package cn.panshi.mongocdc;

import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

import org.bson.Document;
import org.springframework.data.util.Pair;

import lombok.Data;

/**
 * memo:基于Mongodb的ttl index定时索引和change stream机制实现可扩展的延迟（定时）任务。
 * --每个任务由CdcTtlTaskTrigger和CdcTtlTaskDoc一前一后两条记录组成，
 * --前者用于到期触发：为其ttlTime字段建ttl index定时索引，mongodb会在ttlTime值对应时间点（最多延迟一分钟）删除该CdcTtlTaskTrigger记录，
 * --通过订阅删除事件的change stream即可实现定时任务的逻辑调用，
 * --由于删除事件的change stream只能得到id，因此需要在对应的CdcTtlTaskDoc通过triggerId关联；
 */
@Data
@SuppressWarnings("rawtypes")
public class CdcTtlTaskDoc {
	public static final String TABLE = "CdcTtlTask";

	private String id;

	private String triggerId;

	private String name;

	private String type;

	private String typeEnumClass;

	private Date crt;

	private Date scheduleTime;

	private Document taskBizData;

	private Date executedTime;

	private Date unscheduleTime;

	private String executionMemo;

	@Data
	public static class CdcTtlTaskTrigger {
		private String id;

		private Date ttlTime;
	}

	/**
	 * 准备一对儿记录，用于创建新的ttl任务
	 */
	public static Pair<CdcTtlTaskTrigger, CdcTtlTaskDoc> prepareNewTask(String name, Enum type, Document taskBizData,
			Date scheduleTime) {
		CdcTtlTaskTrigger trigger = new CdcTtlTaskTrigger();
		trigger.setId(UUID.randomUUID().toString());
		trigger.setTtlTime(scheduleTime);

		CdcTtlTaskDoc task = new CdcTtlTaskDoc();
		task.setCrt(new Date());
		task.setName(name);
		task.setScheduleTime(scheduleTime);
		task.setTaskBizData(taskBizData);
		task.setTriggerId(trigger.getId());
		task.setType(type.name());
		task.setTypeEnumClass(type.getClass().getName());

		return Pair.of(trigger, task);
	}

	public static Pair<CdcTtlTaskTrigger, CdcTtlTaskDoc> prepareNewTask(String name, Enum type, Document taskBizData,
			int scheduleSecondsLater) {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.SECOND, scheduleSecondsLater);
		Date triggeredTime = cal.getTime();

		return prepareNewTask(name, type, taskBizData, triggeredTime);
	}
}